#pragma once
#include <iostream>
#include <string>
#include <unistd.h>
#include <pthread.h>
#include <cstring>
#include <cerrno>
#include <functional>
enum ExitErrno
{
    DetachError = 1,
    JoinError,
    ExitError,
    CancelError,
    StartError
};

//typedef std::function<void()> func_t;
template<class T, class R>
using func_t = std::function<R(T)>;

// 我们要封装一下pthread库，实际上就是封装其借口，让上层用户访问到即可
// thread的相关接口
// 创建：pthread_create \ 终止：pthread_exit 、pthread_cancel \ 分离：pthread_detach \ 等待：pthread_join \ 获取tid：pthread_self
template <class T, class R>
class Thread
{
public:
    Thread(func_t<T, R> func, T args, std::string name)
        : _tid(0)
        , _isrunning(false)
        , _name(name)
        , _func(func)
        , _retval(R())
        , _args(args)
        , _attr(pthread_attr_t())
    {}

    static void* Handler(void* args)
    {
        Thread* _t = static_cast<Thread*>(args);
        return (void*)(_t->_func(_t->_args));
    }

    //线程真正创建，开始运行
    void Start()
    {
        int ret = pthread_create(&_tid, &_attr, Handler, static_cast<void*>(this));
        if(ret != 0)
        {
            std::cout << "Start error" << ", errno : " << 
            errno << ", strerror : " << strerror(errno) << std::endl;
            exit(StartError);
        } 
        _isrunning = true;
    }
    
    //等待回收
    void Join()
    { 
        _isrunning = false;
        int ret = pthread_join(_tid, (void**)(&_retval));
        if(ret != 0)
        {
            std::cout << "Join error" << ", errno : " << 
            errno << ", strerror : " << strerror(errno) << std::endl;
            exit(JoinError);
        }
    }
    //拿thread id
    pthread_t GetTid()
    {
        return _tid;
    }
    //拿线程名字
    std::string& GetThreadName()
    {
        return _name;
    }
    //看thread是否运行
    bool IsRunning()
    {
        return _isrunning;
    }
    //得到线程属性
    const pthread_attr_t GetAttr()
    {
        return _attr;
    }
    R GetRetVal()
    {
        return _retval;
    }

private:
    pthread_t _tid;    //线程id
    bool _isrunning;   //线程是否运行
    std::string _name; //线程名字
    func_t<T, R> _func;      //线程执行方法
    R _retval;         //执行方法的返回值
    T _args;           //执行方法的参数
    const pthread_attr_t _attr; //线程属性
};
// class thread
// {
// public:
// private:
//     Thread<R, T>* _t;
// };